/*---------------------------------------------------------------------------------------------------------*/
/*                                                                                                         */
/* Copyright(c) 2019 Nuvoton Technology Corp. All rights reserved.                                         */
/*                                                                                                         */
/*---------------------------------------------------------------------------------------------------------*/

//***********************************************************************************************************
//  Website: http://www.nuvoton.com
//  E-Mail : MicroC-8bit@nuvoton.com
//***********************************************************************************************************
#include "MS51_16K.H"



volatile unsigned char xdata page_buffer[128];

/**
 * @brief       Read Dataflash 
 * @param       Dataflash start address
 * @return      Dataflash Value
 * @details     None
 */
unsigned char Read_APROM_BYTE(unsigned int code *u16_addr)
{
    UINT8 rdata;
    rdata = *u16_addr>>8;
    return rdata;
}


/**
 * @brief       Write Dataflash as EEPROM, 
 * @param       u16EPAddr the 16bit EEPROM start address. Any of APROM address can be defined as start address (0x3800)
 * @param       u8EPData the 8bit value need storage in (0x3800)
 * @return      none
 * @details     Storage dataflash page data into XRAM 380H-400H, modify data in XRAM, Erase dataflash page, writer updated XRAM data into dataflash
 */
void Write_DATAFLASH_BYTE(unsigned int u16EPAddr,unsigned char u8EPData)
{
  unsigned char looptmp=0;
  unsigned int u16_addrl_r;
  unsigned int RAMtmp;
  
//Check page start address
  u16_addrl_r=(u16EPAddr/128)*128;
//Save APROM data to XRAM0
  for(looptmp=0;looptmp<0x80;looptmp++)
  {
    RAMtmp = Read_APROM_BYTE((unsigned int code *)(u16_addrl_r+looptmp));
    page_buffer[looptmp]=RAMtmp;
  }
// Modify customer data in XRAM
  page_buffer[u16EPAddr&0x7f] = u8EPData;
  
//Erase APROM DATAFLASH page
    IAPAL = u16_addrl_r&0xff;
    IAPAH = (u16_addrl_r>>8)&0xff;
    IAPFD = 0xFF;
    set_CHPCON_IAPEN; 
    set_IAPUEN_APUEN;
    IAPCN = 0x22;     
     set_IAPTRG_IAPGO; 
    
//Save changed RAM data to APROM DATAFLASH
    set_CHPCON_IAPEN; 
    set_IAPUEN_APUEN;
    IAPCN = 0x21;
    for(looptmp=0;looptmp<0x80;looptmp++)
    {
      IAPAL = (u16_addrl_r&0xff)+looptmp;
      IAPAH = (u16_addrl_r>>8)&0xff;
      IAPFD = page_buffer[looptmp];
      set_IAPTRG_IAPGO;      
    }
    clr_IAPUEN_APUEN;
    clr_CHPCON_IAPEN;
}  


//-------------------------------------------------------------------------
void Write_DATAFLASH_ARRAY(unsigned int u16_addr,unsigned char *pDat,unsigned int num)
{
  unsigned char CPageAddr,EPageAddr,cnt;
  CPageAddr=u16_addr>>7;
  EPageAddr=(u16_addr+num)>>7;
  while(CPageAddr!=EPageAddr)
  {
    cnt=WriteDataToOnePage(u16_addr,pDat,128);
    u16_addr+=cnt;
    pDat+=cnt;
    num-=cnt;
    CPageAddr=u16_addr>>7;
  }
  if(num)
  {
    WriteDataToOnePage(u16_addr,pDat,num);
  }
}
//-------------------------------------------------------------------------
void Read_DATAFLASH_ARRAY(unsigned int u16_addr,unsigned char *pDat,unsigned int num)
{
  unsigned int i;
  for(i=0;i<num;i++)
    pDat[i] = *(unsigned char code *)(u16_addr+i);
}

//-----------------------------------------------------------------------------------------------------------
unsigned char WriteDataToOnePage(unsigned int u16_addr,const unsigned char *pDat,unsigned char num)
{
  unsigned char i,offset;
  unsigned char code *pCode;
  unsigned char xdata xd_tmp[128];

  set_CHPCON_IAPEN; 
  set_IAPUEN_APUEN;

  offset=u16_addr&0x007F;
  i = PAGE_SIZE - offset;
  if(num>i)num=i;
  pCode = (unsigned char code *)u16_addr;
  for(i=0;i<num;i++)
  {
    if(pCode[i]!=0xFF)break;
  }
  if(i==num)
  {
    IAPCN =BYTE_PROGRAM_APROM;
    IAPAL = u16_addr;
    IAPAH = u16_addr>>8;
    for(i=0;i<num;i++)
    {
      IAPFD = pDat[i];
      set_IAPTRG_IAPGO;
      IAPAL++;
    }
    for(i=0;i<num;i++)
    {
      if(pCode[i]!=pDat[i])break;
    }
    if(i!=num) goto WriteDataToPage20;
  }
  else
  {
    WriteDataToPage20:
    pCode = (unsigned char code *)(u16_addr&0xff80);
    for(i=0;i<128;i++)
    {
      xd_tmp[i] = pCode[i];
    }
    for(i=0;i<num;i++)
    {
      xd_tmp[offset+i] = pDat[i];
    }
    do
    {
      IAPAL = (u16_addr&0xff80);
      IAPAH = u16_addr>>8;
      IAPCN = PAGE_ERASE_APROM;
      IAPFD = 0xFF;  
      set_IAPTRG_IAPGO; 
      IAPCN =BYTE_PROGRAM_APROM;
      for(i=0;i<128;i++)
      {
        IAPFD = xd_tmp[i];
        set_IAPTRG_IAPGO;
        IAPAL++;
      }
      for(i=0;i<128;i++)
      {
        if(pCode[i]!=xd_tmp[i])break;
      }
    }while(i!=128);
    
  }
  clr_CHPCON_IAPEN;
  
  return num;
}